package com.woniu.cms.goods.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.woniu.cms.goods.core.entity.*;
import com.woniu.cms.goods.core.exception.Asserts;
import com.woniu.cms.goods.core.exception.BusinessException;
import com.woniu.cms.goods.core.mapper.GoodsReturnMapper;
import com.woniu.cms.goods.core.service.IGoodsGetbillMaterialService;
import com.woniu.cms.goods.core.service.IGoodsOutbillMaterialService;
import com.woniu.cms.goods.core.service.IGoodsReturnMaterialService;
import com.woniu.cms.goods.core.service.IGoodsReturnService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.cms.goods.core.util.AspectsMsg;
import com.woniu.common.api.Result;
import com.woniu.common.api.status.Impl.BusinessCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 退料单表 服务实现类
 * </p>
 *
 * @author romantic sheep
 * @since 2022-09-19
 */
@Service
public class GoodsReturnServiceImpl extends ServiceImpl<GoodsReturnMapper, GoodsReturn> implements IGoodsReturnService {

    @Autowired
    private IGoodsReturnMaterialService returnMaterialService;
    @Autowired
    private IGoodsGetbillMaterialService getbillMaterialService;
    @Autowired
    private IGoodsOutbillMaterialService outbillMaterialService;

    @Override
    @Transactional( propagation = Propagation.REQUIRED  //必须添加事务
            ,timeout = -1         //设置连接永不超时
            ,rollbackFor = {BusinessException.class}  // 抛出异常时进行回滚
            ,isolation = Isolation.DEFAULT                   // 使用数据库的隔离级别
    )
    public Result addReturn(GoodsReturn goodsReturn, List<GoodsReturnMaterial> list) {
        if (ObjectUtils.isEmpty(goodsReturn)){
            return Result.error("请输入必填数据");
        }
        //先保存退料单主表，保存失败抛出异常，事务回滚
        boolean save = this.save(goodsReturn);
        if (!save){
            Asserts.failed(AspectsMsg.SAVE_EXCEPTION);
        }
        //查询退料单主表id，填入材料信息表外键
        LambdaQueryWrapper<GoodsReturn> qw = Wrappers.lambdaQuery();
        qw.eq(GoodsReturn::getReturnNo,goodsReturn.getReturnNo());
        GoodsReturn goodsReturn1 = this.getOne(qw);
        List<GoodsReturnMaterial> collect = list.stream().map(e -> {
            e.setReturnId(goodsReturn1.getId());
            return e;
        }).collect(Collectors.toList());
        //保存材料信息表。保存失败则事务回滚
        boolean b = returnMaterialService.saveBatch(collect);
        if (!b){
            Asserts.failed(AspectsMsg.SAVE_EXCEPTION);
        }
        return Result.ok(BusinessCode.ADD_SUCCESS);
    }

    @Override
    @Transactional( propagation = Propagation.REQUIRED  //必须添加事务
            ,timeout = -1         //设置连接永不超时
            ,rollbackFor = {BusinessException.class}  // 抛出异常时进行回滚
            ,isolation = Isolation.DEFAULT                   // 使用数据库的隔离级别
    )
    public Result deleteReturn(Integer id, Integer status) {
        GoodsReturn goodsReturn = this.getById(id);
        if (ObjectUtils.isEmpty(goodsReturn)){
            return Result.error(BusinessCode.REMOVE_FAIL);
        }
        if (goodsReturn.getStatus()!=0&&goodsReturn.getStatus()!=3){
            return Result.error("单据已提交无法删除");
        }
        //先删除退料单主表，删除失败则抛出异常，事务回滚。
        boolean b = this.removeById(id);
        if (!b){
            Asserts.failed(AspectsMsg.DELETE_EXCEPTION);
        }
        LambdaUpdateWrapper<GoodsReturnMaterial> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(GoodsReturnMaterial::getReturnId,id);
        //再删除退料单材料明细表，删除失败则事务回滚
        boolean remove = returnMaterialService.remove(updateWrapper);
        if (!remove){
            Asserts.failed(AspectsMsg.DELETE_EXCEPTION);
        }
        return Result.ok(BusinessCode.REMOVE_SUCCESS);
    }

    @Override
    @Transactional( propagation = Propagation.REQUIRED  //必须添加事务
            ,timeout = -1         //设置连接永不超时
            ,rollbackFor = {BusinessException.class}  // 抛出异常时进行回滚
            ,isolation = Isolation.DEFAULT                   // 使用数据库的隔离级别
    )
    public Result updateReturn(GoodsReturn goodsReturn, List<GoodsReturnMaterial> list) {
        if (goodsReturn.getStatus()!=0&&goodsReturn.getStatus()!=3){
            return Result.error(BusinessCode.MODIFY_FAIL);
        }
        //先修改退料单主表，修改失败则抛出异常事务回滚
        boolean b = this.updateById(goodsReturn);
        if (!b){
            Asserts.failed(AspectsMsg.UPDATE_EXCEPTION);
        }
        //再修改退料单材料表，修改失败则抛出异常事务回滚
        boolean b1 = returnMaterialService.updateBatchById(list);
        if (!b1){
            Asserts.failed(AspectsMsg.UPDATE_EXCEPTION);
        }
        return Result.ok(BusinessCode.MODIFY_SUCCESS);
    }
    @Override
    @Transactional( propagation = Propagation.REQUIRED  //必须添加事务
            ,timeout = -1         //设置连接永不超时
            ,rollbackFor = {BusinessException.class}  // 抛出异常时进行回滚
            ,isolation = Isolation.DEFAULT                   // 使用数据库的隔离级别
    )
    public Result commitReturn(GoodsReturn goodsReturn, List<GoodsReturnMaterial> list) {
        if (goodsReturn.getStatus()==2){
            return Result.error("单据已提交，无法重复提交");
        }
        //根据退料单引用材料的外键查询对应的领料单材料明细
        List<Integer> outids = list.stream().map(e -> e.getOutbillMaterialId()).collect(Collectors.toList());
        LambdaQueryWrapper<GoodsOutbillMaterial> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.in(GoodsOutbillMaterial::getId,outids);
        List<GoodsOutbillMaterial> outbillMaterials = outbillMaterialService.list(queryWrapper);
        //以外键入库单id排序
        outbillMaterials.sort(new Comparator<GoodsOutbillMaterial>() {
            @Override
            public int compare(GoodsOutbillMaterial o1, GoodsOutbillMaterial o2) {
                return o1.getGetbillMaterialId()-o2.getGetbillMaterialId();
            }
        });
        //根据上面查询的领料单材料明细外键查询出对应的入库单材料明细
        List<Integer> ids = outbillMaterials.stream().map(e -> e.getGetbillMaterialId()).collect(Collectors.toList());
        LambdaQueryWrapper<GoodsGetbillMaterial> qw = Wrappers.lambdaQuery();
        qw.in(GoodsGetbillMaterial::getId,ids);
        List<GoodsGetbillMaterial> getbillMaterials = getbillMaterialService.list(qw);
        //退料单材料明细，根据入库单外键排序
        list.sort(new Comparator<GoodsReturnMaterial>() {
            @Override
            public int compare(GoodsReturnMaterial o1, GoodsReturnMaterial o2) {
                return o1.getGetbillMaterialId()-o2.getGetbillMaterialId();
            }
        });
        //领料单材料明细，根据id排序
        getbillMaterials.sort(new Comparator<GoodsGetbillMaterial>() {
            @Override
            public int compare(GoodsGetbillMaterial o1, GoodsGetbillMaterial o2) {
                return o1.getId()-o2.getId();
            }
        });
        //同一排序规则下材料引用一一对应。首先修改领料单中的真实数量，真实数量-退料数量。
        for (int i=0;i<outbillMaterials.size();i++){

            BigDecimal returnNum = list.get(i).getReturnNum();
            BigDecimal realNum = outbillMaterials.get(i).getRealNum();
            if (returnNum.compareTo(realNum)==1){
                return Result.error("退料数量不得大于现有领料数量");
            }else {
                BigDecimal subtract = realNum.subtract(returnNum);
                GoodsOutbillMaterial goodsOutbillMaterial = outbillMaterials.get(i);
                goodsOutbillMaterial.setRealNum(subtract);
            }
        }
        //修改库存剩余数量，库存剩余数量+退料数量
        for (int i=0;i<getbillMaterials.size();i++){
            BigDecimal returnNum = list.get(i).getReturnNum();
            BigDecimal residueNum = getbillMaterials.get(i).getResidueNum();
            BigDecimal add = residueNum.add(returnNum);
            GoodsGetbillMaterial goodsGetbillMaterial = getbillMaterials.get(i);
            goodsGetbillMaterial.setResidueNum(add);
        }
        goodsReturn.setStatus(1);
        boolean b = this.updateById(goodsReturn);
        if (!b){
            Asserts.failed(AspectsMsg.COMMIT_EXCEPTION);
        }
        boolean b2 = outbillMaterialService.updateBatchById(outbillMaterials);
        if (!b2){
            Asserts.failed(AspectsMsg.COMMIT_EXCEPTION);
        }
        boolean b1 = getbillMaterialService.updateBatchById(getbillMaterials);
        if (!b1){
            Asserts.failed(AspectsMsg.COMMIT_EXCEPTION);
        }
        return Result.ok("单据提交成功");
    }
}

